#ifndef COMMAND_ANALYSER_H
#define COMMAND_ANALYSER_H

#include "../databasemanager/databasemanager.h"
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <iomanip>
#include <ctime>
#include <fstream>

class CommandAnalyser{
public:
    CommandAnalyser() {
        dbm = new DatabaseManager();
        command = "";
        loc = 0;
    };
    ~CommandAnalyser() {
        delete dbm;
    };
private:
    DatabaseManager *dbm;
    std::string command;
    std::vector<std::string> words;
    int loc;
public:
    int find_end_signal(std::string str){
        bool constStr = false;
        for(int i = 0; i < str.length(); ++i){
            if(str[i] == '\''){
                if(i > 0){
                    if(str[i-1] != '\\')
                        constStr = !constStr;
                }
                else
                    constStr = !constStr;
            }
            else if((!constStr) && str[i] == ';')
                return i;
        }
        return -1;
    }
    bool isNum(string &str){
        for(int i = 0; i < str.size(); ++i)
            if(str[i] < '0' || str[i] > '9')
                return false;
        return true;
    }
    string lowercase(string &str){
        string res = str;
        for(int i = 0; i < res.size(); ++i){
            if(res[i] >= 'A' && res[i] <= 'Z')
                res[i] += 'a'-'A';
        }
        return res;
    }
    void getCommand(){
        while(true){
            std::cout << ">>> ";
            std::string tempCmd;
            getline(std::cin, tempCmd);
            command += " " + tempCmd;
            while(true){
                int signalPos = find_end_signal(command);
                if(signalPos == -1)
                    break;
                else{
                    tempCmd = command.substr(0,signalPos);
                    for(int i = 0; i < tempCmd.size(); ++i){
                        if(tempCmd[i] != ' '){
                            tempCmd = tempCmd.substr(i);
                            break;
                        }
                    }
                    if(lowercase(tempCmd) == "exit") return;
                    string cmd = tempCmd.substr(0,7);
                    if(lowercase(cmd) == "source "){
                        std::string filename = tempCmd.substr(7);
                        command = "";
                        std::ifstream file(filename.c_str());
                        if(!file.is_open()){
                            std::cout << "Error : File not exist." << std::endl;
                            break;
                        }
                        else{
                            std::string line;
                            while(!file.eof()){
                                getline(file,line);
                                command += line + " ";
                            }
                            continue;
                        }
                    }
                    else{
                        analyseCommand(tempCmd);
                        std::cout << "--- Operation over." << std::endl;
                        command = command.substr(signalPos+1);
                    }
                }
            }
        }
    }
    void syntaxError(){
        std::cout << "Error : syntax error" << std::endl;
    }
    bool MatchToken(string str){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        if(lowercase(words[loc]) == str){
            ++ loc;
            return true;
        }
        else{
            syntaxError();
            return false;
        }
    }
    void analyseCommand(std::string &command){
        loc = 0;
        splitWords(command);
        doProgram();
    }
    void doProgram(){
        if(words.size() < 2){
            syntaxError();
            return;
        }
        else{
            if(lowercase(words[loc]) == "show" && lowercase(words[loc+1]) == "databases"){
                if(loc + 2 == words.size())
                    dbm->showDatabases();
                else
                    syntaxError();
            }
            else if(lowercase(words[loc]) == "create" && lowercase(words[loc+1]) == "database"){
                loc += 2;
                std::string dbName;
                if(getIdentifier(dbName)){
                    if(loc == words.size()){
                        dbm->createDatabase(dbName);
                    }
                    else
                        syntaxError();
                }
            }
            else if(lowercase(words[loc]) == "drop" && lowercase(words[loc+1]) == "database"){
                loc += 2;
                std::string dbName;
                if(getIdentifier(dbName)){
                    if(loc == words.size()){
                        dbm->dropDatabase(dbName);
                    }
                    else
                        syntaxError();
                }
            }
            else if(lowercase(words[loc]) == "use"){
                loc += 1;
                std::string dbName;
                if(getIdentifier(dbName)){
                    if(loc == words.size()){
                        dbm->useDatabase(dbName);
                    }
                    else
                        syntaxError();
                }
            }
            else if(lowercase(words[loc]) == "show" && lowercase(words[loc+1]) == "tables"){
                if(loc + 2 == words.size())
                    dbm->showDatabase();
                else
                    syntaxError();
            }
            else if(lowercase(words[loc]) == "desc"){
                loc += 1;
                std::string tbName;
                if(getIdentifier(tbName)){
                    if(loc == words.size()){
                        dbm->showTable(tbName);
                    }
                    else
                        syntaxError();
                }
            }
            else if(lowercase(words[loc]) == "create" && lowercase(words[loc+1]) == "table"){
                loc += 2;
                std::string tbName;
                std::vector<std::vector<std::string> > fieldList;
                if(getIdentifier(tbName)){
                    if(MatchToken("(")){
                        if(getFieldList(fieldList)){
                            if(MatchToken(")")){
                                if(loc == words.size()){
                                    std::string primary_key = "";
                                    std::vector<TableColumn> tcList;
                                    for(int i = 0; i < fieldList.size(); ++i){
                                        if(fieldList[i][0] == "3") {
                                            if(primary_key != ""){
                                                std::cout << "Error : Multiple primary key" << std::endl;
                                                return;
                                            }
                                            primary_key = fieldList[i][1];
                                        }
                                    }
                                    for(int i = 0; i < fieldList.size(); ++i){
                                        if(fieldList[i][0] == "1" || fieldList[i][0] == "2") {
                                            if(lowercase(fieldList[i][2]) != "int" && lowercase(fieldList[i][2]) != "char" && lowercase(fieldList[i][2]) != "varchar"){
                                                std::cout << "Error : Illegal column type" << std::endl;
                                                return;
                                            }
                                            if(!isNum(fieldList[i][3])){
                                                std::cout << "Error : Column lenth must be a number" << std::endl;
                                                return;
                                            }
                                            tcList.push_back(TableColumn(fieldList[i][1],lowercase(fieldList[i][2]).substr(0,1),atoi(fieldList[i][3].c_str()), fieldList[i][0] == "1"));
                                        }
                                    }
                                    std::vector<bool> hasCheck;
                                    std::vector<int> posCheck;
                                    for(int i = 0; i < tcList.size(); ++i) hasCheck.push_back(false);
                                    for(int i = 0; i < tcList.size(); ++i) posCheck.push_back(-1);
                                    for(int i = 0; i < fieldList.size(); ++i){
                                        if(fieldList[i][0] == "4") {
                                            int col = -1;
                                            for(int j = 0; j < tcList.size(); ++j){
                                                if(tcList[j].column_name == fieldList[i][1]){
                                                    if(hasCheck[j]){
                                                        std::cout << "Error : Multiple check limit." << std::endl;
                                                        return;
                                                    }
                                                    else{
                                                        col = j;
                                                        hasCheck[j] = true;
                                                        break;
                                                    }
                                                }
                                            }
                                            if(col != -1){
                                                posCheck[col] = i;
                                                for(int j = 2; j < fieldList[i].size(); ++j){
                                                    if(fieldList[i][j] == "null"){
                                                        syntaxError();
                                                        return;
                                                    }
                                                    if(fieldList[i][j][0] == '\''){
                                                        if(tcList[col].type != "c" && tcList[col].type != "v" ){
                                                            std::cout << "Error : Unmatched check type." << std::endl;
                                                            return;
                                                        }
                                                    }
                                                    else{
                                                        if(tcList[col].type != "i" ){
                                                            std::cout << "Error : Unmatched check type." << std::endl;
                                                            return;
                                                        }
                                                    }
                                                }
                                            }
                                            else{
                                                std::cout << "Error : Invalid check column." << std::endl;
                                                return;
                                            }
                                        }
                                    }
                                    dbm->createTable(tbName, tcList, primary_key);
                                    std::vector<TableColumn> checkTc;
                                    for(int i = 0; i < tcList.size(); ++i){
                                        if(posCheck[i] != -1){
                                            checkTc.clear();
                                            std::string check_tn = SYS_CHECK + tbName + "_" + tcList[i].column_name;
                                            checkTc.push_back(TableColumn("value", tcList[i].type, tcList[i].length, tcList[i].isNull));
                                            dbm->createTable(check_tn, checkTc, "");
                                            for(int j = 2; j < fieldList[posCheck[i]].size(); ++j){
                                                if(fieldList[posCheck[i]][j][0] == '\''){
                                                    Data checkData;
                                                    checkData.insertValue(fieldList[posCheck[i]][j].substr(1, fieldList[posCheck[i]][j].size()-2));
                                                    dbm->getDataManager()->insertData(checkData, check_tn);
                                                }
                                                else{
                                                    Data checkData;
                                                    checkData.insertValue(fieldList[posCheck[i]][j]);
                                                    dbm->getDataManager()->insertData(checkData, check_tn);
                                                }
                                            }
                                        }
                                    }
                                }
                                else{
                                    syntaxError();
                                }
                            }
                        }
                    }
                }
            }
            else if(lowercase(words[loc]) == "insert" && lowercase(words[loc+1]) == "into"){
                loc += 2;
                std::string tbName;
                std::vector<std::vector<std::string> > valueLists;
                if(getIdentifier(tbName)){
                    if(MatchToken("values")){
                        if(getValueLists(valueLists))
                        {
                            if(loc == words.size()){
                                search_result table_cols;
                                dbm->getTableColumns(tbName, table_cols);
                                search_result checkExists;
                                std::vector<search_condition> condition;
                                std::vector<std::vector<std::string> > checkList;
                                std::vector<std::string> val;
                                for(int i = 0; i < table_cols.size(); ++i){
                                    val.clear();
                                    condition.clear();
                                    condition.push_back(search_condition(N_TABLE_NAME, SYS_CHECK + tbName + "_" + table_cols[i][N_COLUMN_NAME]));
                                    dbm->getDataManager()->searchData(condition, SYS_OBJ, checkExists);
                                    if(checkExists.size() == 0) checkList.push_back(val);
                                    else{
                                        condition.clear();
                                        dbm->getDataManager()->searchData(condition, SYS_CHECK + tbName + "_" + table_cols[i][N_COLUMN_NAME], checkExists);
                                        for(int j = 0 ; j < checkExists.size(); ++j) val.push_back(checkExists[j][1].c_str());
                                        checkList.push_back(val);
                                    }
                                }
                                for(int i = 0; i < valueLists.size(); ++i){
                                    if(table_cols.size() != valueLists[i].size()){
                                        std::cout << "Error : Unmatched column number." << std::endl;
                                        continue;
                                    }
                                    Data newData;
                                    bool illegal = false;
                                    for(int j = 0; j < table_cols.size(); ++j){
                                        if(valueLists[i][j] == "null"){
                                            if(table_cols[j][N_COLUMN_NULL] == "1")
                                                newData.insertNull();
                                            else{
                                                illegal = true;
                                                std::cout << "Error : Null is not acceptable in certain column." << std::endl;
                                                break;
                                            }
                                        }
                                        else if(valueLists[i][j][0] == '\''){
                                            if(checkList[j].size() != 0){
                                                bool found = false;
                                                std::string checkStr = valueLists[i][j].substr(1,valueLists[i][j].size()-2);
                                                for(int k = 0; k < checkList[j].size(); ++k){
                                                    if(checkStr == checkList[j][k]){
                                                        found = true;
                                                        break;
                                                    }
                                                }
                                                if(!found){
                                                    illegal = true;
                                                    std::cout << "Error : Dissatisfy domain constraints." << std::endl;
                                                    break;
                                                }
                                            }
                                            if(table_cols[j][N_COLUMN_TYPE][0] == 'c' || table_cols[j][N_COLUMN_TYPE][0] == 'v')
                                                newData.insertValue(valueLists[i][j].substr(1,valueLists[i][j].size()-2));
                                            else{
                                                illegal = true;
                                                std::cout << "Error : Unmatched value type." << std::endl;
                                                break;
                                            }
                                        }
                                        else{
                                            if(checkList[j].size() != 0){
                                                bool found = false;
                                                for(int k = 0; k < checkList[j].size(); ++k){
                                                    if(valueLists[i][j] == checkList[j][k]){
                                                        found = true;
                                                        break;
                                                    }
                                                }
                                                if(!found){
                                                    illegal = true;
                                                    std::cout << "Error : Dissatisfy domain constraints." << std::endl;
                                                    break;
                                                }
                                            }
                                            if(table_cols[j][N_COLUMN_TYPE][0] == 'i')
                                                newData.insertValue(valueLists[i][j]);
                                            else{
                                                illegal = true;
                                                std::cout << "Error : Unmatched value type." << std::endl;
                                                break;
                                            }
                                        }
                                    }
                                    if(!illegal){
                                        dbm->getDataManager()->insertData(newData, tbName);
                                    }
                                }
                            }
                            else
                                syntaxError();
                        }
                    }
                }
            }
            else if(lowercase(words[loc]) == "create" && lowercase(words[loc+1]) == "index"){
                loc += 2;
                std::string tbName, colName;
                if(getIdentifier(tbName)){
                    if(MatchToken("(")){
                        if(getIdentifier(colName)){
                            if(MatchToken(")")){
                                if(loc == words.size()){
                                    search_result table_cols;
                                    dbm->getTableColumns(tbName, table_cols);
                                    int col = -1;
                                    for(int i = 0; i < table_cols.size(); ++i){
                                        if(table_cols[i][N_COLUMN_NAME] == Data::fillStr(colName, table_cols[i][N_COLUMN_NAME].size())){
                                            col = Data::intUnzip(&(table_cols[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            break;
                                        }
                                    }
                                    if(col == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    else{
                                        dbm->getDataManager()->addIndex(tbName, col);
                                    }
                                }
                                else
                                    syntaxError();
                            }
                        }
                    }
                }
            }
            else if(lowercase(words[loc]) == "drop" && lowercase(words[loc+1]) == "index"){
                loc += 2;
                std::string tbName, colName;
                if(getIdentifier(tbName)){
                    if(MatchToken("(")){
                        if(getIdentifier(colName)){
                            if(MatchToken(")")){
                                if(loc == words.size()){
                                    search_result table_cols;
                                    dbm->getTableColumns(tbName, table_cols);
                                    int col = -1;
                                    for(int i = 0; i < table_cols.size(); ++i){
                                        if(table_cols[i][N_COLUMN_NAME] == Data::fillStr(colName, table_cols[i][N_COLUMN_NAME].size())){
                                            col = Data::intUnzip(&(table_cols[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            break;
                                        }
                                    }
                                    if(col == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    else{
                                        dbm->getDataManager()->removeIndex(tbName, col);
                                    }
                                }
                                else
                                    syntaxError();
                            }
                        }
                    }
                }
            }
            else if(lowercase(words[loc]) == "drop" && lowercase(words[loc+1]) == "table"){
                loc += 2;
                std::string tbName;
                if(getIdentifier(tbName)){
                    if(loc == words.size()){
                        dbm->dropTable(tbName);
                    }
                    else
                        syntaxError();
                }
            }
            else if(lowercase(words[loc]) == "delete" && lowercase(words[loc+1]) == "from"){
                loc += 2;
                std::string tbName;
                std::vector<std::vector<std::string> > whereClause;
                bool syntaxSuccess = false;
                if(getIdentifier(tbName)){
                    if(loc == words.size())
                        syntaxSuccess = true;
                    else if(lowercase(words[loc]) == "where"){
                        MatchToken("where");
                        if(getWhereClause(whereClause)){
                            if(loc == words.size())
                                syntaxSuccess = true;
                            else
                                syntaxError();
                        }
                    }
                    else
                        syntaxError();
                }
                if(syntaxSuccess){
                    std::vector<std::string> cols;
                    std::vector<std::vector<std::string> > table_cols;
                    std::vector<search_condition> condition;
                    search_result res;
                    condition.clear();
                    dbm->getTableColumns(tbName, table_cols);
                    for(int i = 0 ; i < whereClause.size(); ++i){
                        if(whereClause[i][1] != "" && whereClause[i][1] != tbName){
                            std::cout << "Error : Unmatched table and columns." << std::endl;
                            return;
                        }
                        if(whereClause[i][0] == "1"){
                            int col = -1;
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                    col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                    break;
                                }
                            }
                            if(col == -1){
                                std::cout << "Error : Column not found" << std::endl;
                                return;
                            }
                            else
                                condition.push_back(search_condition(WHERE_NULL * MAX_COLUMN_NUM + col, ""));
                        }
                        else if(whereClause[i][0] == "2"){
                            int col = -1;
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                    col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                    break;
                                }
                            }
                            if(col == -1){
                                std::cout << "Error : Column not found" << std::endl;
                                return;
                            }
                            else
                                condition.push_back(search_condition(WHERE_NOT_NULL * MAX_COLUMN_NUM + col, ""));
                        }
                        else{
                            int col = -1, colr;
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                    col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                    colr = j;
                                    break;
                                }
                            }
                            if(col == -1){
                                std::cout << "Error : Column not found" << std::endl;
                                return;
                            }
                            else{
                                if(whereClause[i][4] == "1"){
                                    if(whereClause[i][3] == "<"
                                    || whereClause[i][3] == ">"
                                    || whereClause[i][3] == "<="
                                    || whereClause[i][3] == ">=")
                                        if(table_cols[colr][N_COLUMN_TYPE][0] != 'i' || whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'){
                                            std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                            return;
                                        }
                                    if((table_cols[colr][N_COLUMN_TYPE][0] == 'i' && (whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'))
                                    || ((table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') &&  whereClause[i][5][0] != '\'')
                                    || whereClause[i][5] == "null"){
                                        std::cout << "Error : Unmatched compare objects." << std::endl;
                                        return;
                                    }
                                    std::string target;
                                    if(table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') target = whereClause[i][5].substr(1,whereClause[i][5].size()-2);
                                    else target = whereClause[i][5];
                                    int op = -1;
                                    if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                    else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                    else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                    else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                    else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                    else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                    else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                    condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col, target));
                                }
                                else{
                                    if(whereClause[i][5] != "" && whereClause[i][5] != tbName){
                                        std::cout << "Error : Unmatched table and columns." << std::endl;
                                        return;
                                    }
                                    int col2 = -1;
                                    string type2;
                                    for(int j = 0; j < table_cols.size(); ++j){
                                        if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][6], table_cols[j][N_COLUMN_NAME].size())){
                                            col2 = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            type2 = table_cols[j][N_COLUMN_TYPE];
                                            break;
                                        }
                                    }
                                    if(col2 == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    if(whereClause[i][3] == "<"
                                    || whereClause[i][3] == ">"
                                    || whereClause[i][3] == "<="
                                    || whereClause[i][3] == ">=")
                                        if(table_cols[colr][N_COLUMN_TYPE][0] != 'i'){
                                            std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                            return;
                                        }
                                    if(table_cols[colr][N_COLUMN_TYPE] != type2){
                                        std::cout << "Error : Unmatched compare objects." << std::endl;
                                        return;
                                    }
                                    std::string target;
                                    std::stringstream ss;
                                    ss << col2;
                                    ss >> target;
                                    int op = -1;
                                    if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                    else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                    else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                    else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                    else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                    else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                    else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                    condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_COL) * MAX_COLUMN_NUM + col, target));
                                }
                            }
                        }
                    }
                    dbm->getDataManager()->deleteData(condition, tbName);
                }
            }
            else if(lowercase(words[loc]) == "update"){
                loc += 1;
                std::string tbName;
                std::vector<std::vector<std::string> > whereClause;
                std::vector<std::vector<std::string> > setClause;
                bool syntaxSuccess = false;
                if(getIdentifier(tbName)){
                    if(MatchToken("set")){
                        if(getSetClause(setClause)){
                            if(loc == words.size())
                                syntaxSuccess = true;
                            else if(lowercase(words[loc]) == "where"){
                                MatchToken("where");
                                if(getWhereClause(whereClause)){
                                    if(loc == words.size())
                                        syntaxSuccess = true;
                                    else
                                        syntaxError();
                                }
                            }
                            else
                                syntaxError();
                        }
                    }
                }
                if(syntaxSuccess){
                    std::vector<std::string> cols;
                    std::vector<std::vector<std::string> > table_cols;
                    std::vector<search_condition> condition;
                    std::vector<replace_pair> replace;
                    search_result res;
                    condition.clear();
                    dbm->getTableColumns(tbName, table_cols);
                    for(int i = 0; i < setClause.size(); ++i){
                        int col = -1;
                        std::string type;
                        for(int j = 0; j < table_cols.size(); ++j){
                            if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(setClause[i][0], table_cols[j][N_COLUMN_NAME].size())){
                                col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                type = table_cols[j][N_COLUMN_TYPE];
                                break;
                            }
                        }
                        if(col == -1){
                            std::cout << "Error : Column not found" << std::endl;
                            return;
                        }
                        if(setClause[i][1] == "null"){
                            replace.push_back(replace_pair(MAX_COLUMN_NUM+col, ""));
                        }
                        else if(setClause[i][1][0] == '\''){
                            if(type[0] != 'c' && type[0] != 'v'){
                                std::cout << "Error : Unmatched column type." << std::endl;
                                return;
                            }
                            replace.push_back(replace_pair(col, setClause[i][1].substr(1,setClause[i][1].size()-2)));
                        }
                        else{
                            if(type[0] != 'i'){
                                std::cout << "Error : Unmatched column type." << std::endl;
                                return;
                            }
                            replace.push_back(replace_pair(col, setClause[i][1]));
                        }
                    }
                    for(int i = 0; i < whereClause.size(); ++i){
                        if(whereClause[i][1] != "" && whereClause[i][1] != tbName){
                            std::cout << "Error : Unmatched table and columns." << std::endl;
                            return;
                        }
                        if(whereClause[i][0] == "1"){
                            int col = -1;
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                    col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                    break;
                                }
                            }
                            if(col == -1){
                                std::cout << "Error : Column not found" << std::endl;
                                return;
                            }
                            else
                                condition.push_back(search_condition(WHERE_NULL * MAX_COLUMN_NUM + col, ""));
                        }
                        else if(whereClause[i][0] == "2"){
                            int col = -1;
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                    col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                    break;
                                }
                            }
                            if(col == -1){
                                std::cout << "Error : Column not found" << std::endl;
                                return;
                            }
                            else
                                condition.push_back(search_condition(WHERE_NOT_NULL * MAX_COLUMN_NUM + col, ""));
                        }
                        else{
                            int col = -1, colr;
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                    col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                    colr = j;
                                    break;
                                }
                            }
                            if(col == -1){
                                std::cout << "Error : Column not found" << std::endl;
                                return;
                            }
                            else{
                                if(whereClause[i][4] == "1"){
                                    if(whereClause[i][3] == "<"
                                    || whereClause[i][3] == ">"
                                    || whereClause[i][3] == "<="
                                    || whereClause[i][3] == ">=")
                                        if(table_cols[colr][N_COLUMN_TYPE][0] != 'i' || whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'){
                                            std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                            return;
                                        }
                                    if((table_cols[colr][N_COLUMN_TYPE][0] == 'i' && (whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'))
                                    || ((table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') &&  whereClause[i][5][0] != '\'')
                                    || whereClause[i][5] == "null"){
                                        std::cout << "Error : Unmatched compare objects." << std::endl;
                                        return;
                                    }
                                    std::string target;
                                    if(table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') target = whereClause[i][5].substr(1,whereClause[i][5].size()-2);
                                    else target = whereClause[i][5];
                                    int op = -1;
                                    if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                    else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                    else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                    else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                    else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                    else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                    else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                    condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col, target));
                                }
                                else{
                                    if(whereClause[i][5] != "" && whereClause[i][5] != tbName){
                                        std::cout << "Error : Unmatched table and columns." << std::endl;
                                        return;
                                    }
                                    int col2 = -1;
                                    string type2;
                                    for(int j = 0; j < table_cols.size(); ++j){
                                        if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][6], table_cols[j][N_COLUMN_NAME].size())){
                                            col2 = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            type2 = table_cols[j][N_COLUMN_TYPE];
                                            break;
                                        }
                                    }
                                    if(col2 == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    if(whereClause[i][3] == "<"
                                    || whereClause[i][3] == ">"
                                    || whereClause[i][3] == "<="
                                    || whereClause[i][3] == ">=")
                                        if(table_cols[colr][N_COLUMN_TYPE][0] != 'i'){
                                            std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                            return;
                                        }
                                    if(table_cols[colr][N_COLUMN_TYPE] != type2){
                                        std::cout << "Error : Unmatched compare objects." << std::endl;
                                        return;
                                    }
                                    std::string target;
                                    std::stringstream ss;
                                    ss << col2;
                                    ss >> target;
                                    int op = -1;
                                    if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                    else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                    else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                    else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                    else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                    else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                    else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                    condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_COL) * MAX_COLUMN_NUM + col, target));
                                }
                            }
                        }
                    }
                    dbm->getDataManager()->updateData(condition, tbName, replace);
                }
            }
            else if(lowercase(words[loc]) == "select" &&
                (lowercase(words[loc+1]) == "sum" ||
                 lowercase(words[loc+1]) == "avg" ||
                 lowercase(words[loc+1]) == "max" ||
                 lowercase(words[loc+1]) == "min" )){
                std::string operation = lowercase(words[loc+1]);
                loc += 2;
                std::string tbName;
                std::vector<std::vector<std::string> > whereClause;
                std::vector<std::string> selector;
                std::vector<std::string> tableList;
                bool syntaxSuccess = false;
                if(!MatchToken("(")) return;
                if(getSelector(selector)){
                    if(!MatchToken(")")) return;
                    if(MatchToken("from")){
                        if(getIdentifier(tbName)){
                            if(loc == words.size())
                                syntaxSuccess = true;
                            else if(lowercase(words[loc]) == "where"){
                                MatchToken("where");
                                if(getWhereClause(whereClause)){
                                    if(loc == words.size())
                                        syntaxSuccess = true;
                                    else
                                        syntaxError();
                                }
                            }
                            else
                                syntaxError();
                        }
                    }
                }
                if(syntaxSuccess){
                    if(true){
                        std::vector<std::string> cols;
                        std::vector<std::vector<std::string> > table_cols;
                        std::vector<int> select_cols;
                        if(selector[0] == "*"){
                            dbm->getTableColumns(tbName, table_cols);
                            if(table_cols.size() == 0) return;
                            for(int i = 0; i < table_cols.size(); ++i)
                                select_cols.push_back(Data::intUnzip(&(table_cols[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK));
                        }
                        else{
                            for(int i = 0; i < selector.size(); i+=2){
                                if(selector[i] != "" && selector[i] != tbName){
                                    std::cout << "Error : Unmatched table and columns." << std::endl;
                                    return;
                                }
                                else
                                    cols.push_back(selector[i+1]);
                            }
                            dbm->getTableColumns(tbName, table_cols);
                            if(table_cols.size() == 0) return;
                            for(int k = 0; k < cols.size(); ++k){
                                int col = -1;
                                for(int i = 0; i < table_cols.size(); ++i){
                                    if(table_cols[i][N_COLUMN_NAME] == Data::fillStr(cols[k], table_cols[i][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else
                                    select_cols.push_back(col);
                            }
                        }
                        std::vector<search_condition> condition;
                        search_result res;
                        condition.clear();
                        for(int i = 0 ; i < whereClause.size(); ++i){
                            if(whereClause[i][1] != "" && whereClause[i][1] != tbName){
                                std::cout << "Error : Unmatched table and columns." << std::endl;
                                return;
                            }
                            if(whereClause[i][0] == "1"){
                                int col = -1;
                                for(int j = 0; j < table_cols.size(); ++j){
                                    if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else
                                    condition.push_back(search_condition(WHERE_NULL * MAX_COLUMN_NUM + col, ""));
                            }
                            else if(whereClause[i][0] == "2"){
                                int col = -1;
                                for(int j = 0; j < table_cols.size(); ++j){
                                    if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else
                                    condition.push_back(search_condition(WHERE_NOT_NULL * MAX_COLUMN_NUM + col, ""));
                            }
                            else{
                                int col = -1, colr;
                                for(int j = 0; j < table_cols.size(); ++j){
                                    if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        colr = j;
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else{
                                    if(whereClause[i][4] == "1"){
                                        if(whereClause[i][3] == "<"
                                        || whereClause[i][3] == ">"
                                        || whereClause[i][3] == "<="
                                        || whereClause[i][3] == ">=")
                                            if(table_cols[colr][N_COLUMN_TYPE][0] != 'i' || whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'){
                                                std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                                return;
                                            }
                                        if((table_cols[colr][N_COLUMN_TYPE][0] == 'i' && (whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'))
                                        || ((table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') &&  whereClause[i][5][0] != '\'')
                                        || whereClause[i][5] == "null"){
                                            std::cout << "Error : Unmatched compare objects." << std::endl;
                                            return;
                                        }
                                        std::string target;
                                        if(table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') target = whereClause[i][5].substr(1,whereClause[i][5].size()-2);
                                        else target = whereClause[i][5];
                                        int op = -1;
                                        if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                        else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                        else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                        else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                        else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                        else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                        else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                        condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col, target));
                                    }
                                    else{
                                        if(whereClause[i][5] != "" && whereClause[i][5] != tbName){
                                            std::cout << "Error : Unmatched table and columns." << std::endl;
                                            return;
                                        }
                                        int col2 = -1;
                                        string type2;
                                        for(int j = 0; j < table_cols.size(); ++j){
                                            if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][6], table_cols[j][N_COLUMN_NAME].size())){
                                                col2 = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                                type2 = table_cols[j][N_COLUMN_TYPE];
                                                break;
                                            }
                                        }
                                        if(col2 == -1){
                                            std::cout << "Error : Column not found" << std::endl;
                                            return;
                                        }
                                        if(whereClause[i][3] == "<"
                                        || whereClause[i][3] == ">"
                                        || whereClause[i][3] == "<="
                                        || whereClause[i][3] == ">=")
                                            if(table_cols[colr][N_COLUMN_TYPE][0] != 'i'){
                                                std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                                return;
                                            }
                                        if(table_cols[colr][N_COLUMN_TYPE] != type2){
                                            std::cout << "Error : Unmatched compare objects." << std::endl;
                                            return;
                                        }
                                        std::string target;
                                		std::stringstream ss;
                                		ss << col2;
                                		ss >> target;
                                        int op = -1;
                                        if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                        else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                        else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                        else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                        else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                        else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                        else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                        condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_COL) * MAX_COLUMN_NUM + col, target));
                                    }
                                }
                            }
                        }
                        dbm->getDataManager()->searchData(condition, tbName, res);
                        for(int i = 0; i < select_cols.size(); ++i)
                            for(int j = 0; j < table_cols.size(); ++j){
                                if(Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK) == select_cols[i]){
                                    std::cout << operation << " of " << table_cols[j][N_COLUMN_NAME].c_str() << " : ";
                                    if(table_cols[j][N_COLUMN_TYPE] != "i"){
                                        std::cout << "not integer" << std::endl;
                                        break;
                                    }
                                    double result = 0;
                                    bool isChanged = false;
                                    for(int k = 0; k < res.size(); ++k){
                                        if(operation == "sum" || operation == "avg")
                                            result += atoi(res[k][select_cols[i]].c_str());
                                        else if(operation == "min"){
                                            if(!isChanged || atoi(res[k][select_cols[i]].c_str()) < result){
                                                result = atoi(res[k][select_cols[i]].c_str());
                                                isChanged = true;
                                            }
                                        }
                                        else if(operation == "max"){
                                            if(!isChanged || atoi(res[k][select_cols[i]].c_str()) > result){
                                                result = atoi(res[k][select_cols[i]].c_str());
                                                isChanged = true;
                                            }
                                        }
                                    }
                                    if(operation == "avg") std::cout << setprecision(15) << result/res.size() << std::endl;
                                    else std::cout << setprecision(15) << result << std::endl;
                                }
                            }
                    }
                }
            }
            else if(lowercase(words[loc]) == "select"){
                loc += 1;
                std::string tbName;
                std::vector<std::vector<std::string> > whereClause;
                std::vector<std::string> selector;
                std::vector<std::string> tableList;
                bool syntaxSuccess = false;
                if(getSelector(selector)){
                    if(MatchToken("from")){
                        if(getTableList(tableList)){
                            if(loc == words.size())
                                syntaxSuccess = true;
                            else if(lowercase(words[loc]) == "where"){
                                MatchToken("where");
                                if(getWhereClause(whereClause)){
                                    if(loc == words.size())
                                        syntaxSuccess = true;
                                    else
                                        syntaxError();
                                }
                            }
                            else
                                syntaxError();
                        }
                    }
                }
                if(syntaxSuccess){
                    if(tableList.size() == 1){
                        int t1 = clock();
                        tbName = tableList[0];
                        std::vector<std::string> cols;
                        std::vector<std::vector<std::string> > table_cols;
                        std::vector<int> select_cols;
                        if(selector[0] == "*"){
                            dbm->getTableColumns(tbName, table_cols);
                            if(table_cols.size() == 0) return;
                            for(int i = 0; i < table_cols.size(); ++i)
                                select_cols.push_back(Data::intUnzip(&(table_cols[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK));
                        }
                        else{
                            for(int i = 0; i < selector.size(); i+=2){
                                if(selector[i] != "" && selector[i] != tbName){
                                    std::cout << "Error : Unmatched table and columns." << std::endl;
                                    return;
                                }
                                else
                                    cols.push_back(selector[i+1]);
                            }
                            dbm->getTableColumns(tbName, table_cols);
                            if(table_cols.size() == 0) return;
                            for(int k = 0; k < cols.size(); ++k){
                                int col = -1;
                                for(int i = 0; i < table_cols.size(); ++i){
                                    if(table_cols[i][N_COLUMN_NAME] == Data::fillStr(cols[k], table_cols[i][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else
                                    select_cols.push_back(col);
                            }
                        }
                        std::vector<search_condition> condition;
                        search_result res;
                        condition.clear();
                        for(int i = 0 ; i < whereClause.size(); ++i){
                            if(whereClause[i][1] != "" && whereClause[i][1] != tbName){
                                std::cout << "Error : Unmatched table and columns." << std::endl;
                                return;
                            }
                            if(whereClause[i][0] == "1"){
                                int col = -1;
                                for(int j = 0; j < table_cols.size(); ++j){
                                    if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else
                                    condition.push_back(search_condition(WHERE_NULL * MAX_COLUMN_NUM + col, ""));
                            }
                            else if(whereClause[i][0] == "2"){
                                int col = -1;
                                for(int j = 0; j < table_cols.size(); ++j){
                                    if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else
                                    condition.push_back(search_condition(WHERE_NOT_NULL * MAX_COLUMN_NUM + col, ""));
                            }
                            else{
                                int col = -1, colr;
                                for(int j = 0; j < table_cols.size(); ++j){
                                    if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                        col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                        colr = j;
                                        break;
                                    }
                                }
                                if(col == -1){
                                    std::cout << "Error : Column not found" << std::endl;
                                    return;
                                }
                                else{
                                    if(whereClause[i][4] == "1"){
                                        if(whereClause[i][3] == "<"
                                        || whereClause[i][3] == ">"
                                        || whereClause[i][3] == "<="
                                        || whereClause[i][3] == ">=")
                                            if(table_cols[colr][N_COLUMN_TYPE][0] != 'i' || whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'){
                                                std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                                return;
                                            }
                                        if((table_cols[colr][N_COLUMN_TYPE][0] == 'i' && (whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'))
                                        || ((table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') &&  whereClause[i][5][0] != '\'')
                                        || whereClause[i][5] == "null"){
                                            std::cout << "Error : Unmatched compare objects." << std::endl;
                                            return;
                                        }
                                        std::string target;
                                        if(table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') target = whereClause[i][5].substr(1,whereClause[i][5].size()-2);
                                        else target = whereClause[i][5];
                                        int op = -1;
                                        if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                        else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                        else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                        else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                        else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                        else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                        else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                        condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col, target));
                                    }
                                    else{
                                        if(whereClause[i][5] != "" && whereClause[i][5] != tbName){
                                            std::cout << "Error : Unmatched table and columns." << std::endl;
                                            return;
                                        }
                                        int col2 = -1;
                                        string type2;
                                        for(int j = 0; j < table_cols.size(); ++j){
                                            if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][6], table_cols[j][N_COLUMN_NAME].size())){
                                                col2 = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                                type2 = table_cols[j][N_COLUMN_TYPE];
                                                break;
                                            }
                                        }
                                        if(col2 == -1){
                                            std::cout << "Error : Column not found" << std::endl;
                                            return;
                                        }
                                        if(whereClause[i][3] == "<"
                                        || whereClause[i][3] == ">"
                                        || whereClause[i][3] == "<="
                                        || whereClause[i][3] == ">=")
                                            if(table_cols[colr][N_COLUMN_TYPE][0] != 'i'){
                                                std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                                return;
                                            }
                                        if(table_cols[colr][N_COLUMN_TYPE] != type2){
                                            std::cout << "Error : Unmatched compare objects." << std::endl;
                                            return;
                                        }
                                        std::string target;
                                		std::stringstream ss;
                                		ss << col2;
                                		ss >> target;
                                        int op = -1;
                                        if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                        else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                        else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                        else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                        else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                        else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                        else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                        condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_COL) * MAX_COLUMN_NUM + col, target));
                                    }
                                }
                            }
                        }
                        for(int i = 0; i < select_cols.size(); ++i)
                            for(int j = 0; j < table_cols.size(); ++j)
                                if(Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK) == select_cols[i]){
                                    std::cout << table_cols[j][N_COLUMN_NAME].c_str() << " | ";
                                }
                        std::cout << std::endl;
                        dbm->getDataManager()->searchData(condition, tbName, res);
                        for(int i = 0; i < res.size(); ++i){
                            for(int j = 0; j < select_cols.size(); ++j)
                                std::cout << res[i][select_cols[j]].c_str() << " | ";
                            std::cout << std::endl;
                        }
                        std::cout << std::endl;
                        std::cout << "Time cost : " << clock() - t1 << " ms" << std::endl;
                    }
                    else{
                        int t1 = clock();
                        std::vector<std::vector<std::string> > cols;
                        std::vector<std::vector<int> > select_cols;
                        if(selector[0] == "*"){
                            for(int i = 0; i < tableList.size(); ++i){
                                tbName = tableList[i];
                                std::vector<std::vector<std::string> > table_col;
                                table_col.clear();
                                dbm->getTableColumns(tbName, table_col);
                                if(table_col.size() == 0) return;
                                std::vector<int> select_col;
                                select_col.clear();
                                for(int i = 0; i < table_col.size(); ++i)
                                    select_col.push_back(Data::intUnzip(&(table_col[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK));
                                select_cols.push_back(select_col);
                            }
                        }
                        else{
                            cols.resize(tableList.size());
                            for(int i = 0; i < selector.size(); i+=2){
                                bool found = false;
                                for(int j = 0 ; j < tableList.size(); ++j){
                                    if(selector[i] == tableList[j]){
                                        cols[j].push_back(selector[i+1]);
                                        found = true;
                                        break;
                                    }
                                }
                                if(!found){
                                    std::cout << "Error : Unmatched table and columns." << std::endl;
                                    return;
                                }
                            }
                            for(int k = 0; k < cols.size(); ++k){
                                tbName = tableList[k];
                                std::vector<std::vector<std::string> > table_col;
                                std::vector<int> select_col;
                                select_col.clear();
                                table_col.clear();
                                dbm->getTableColumns(tbName, table_col);
                                if(table_col.size() == 0) return;
                                for(int t = 0; t < cols[k].size(); ++t){
                                    int col = -1;
                                    for(int i = 0; i < table_col.size(); ++i){
                                        if(table_col[i][N_COLUMN_NAME] == Data::fillStr(cols[k][t], table_col[i][N_COLUMN_NAME].size())){
                                            col = Data::intUnzip(&(table_col[i][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            break;
                                        }
                                    }
                                    if(col == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    else
                                        select_col.push_back(col);
                                }
                                select_cols.push_back(select_col);
                            }
                        }
                        std::vector<std::vector<search_condition> > conditions;
                        std::vector<position> replace;
                        std::vector<int> replace_op;
                        for(int u = 0; u < tableList.size(); ++u){
                            tbName = tableList[u];
                            std::vector<std::vector<std::string> > table_cols;
                            std::vector<search_condition> condition;
                            condition.clear();
                            for(int i = 0 ; i < whereClause.size(); ++i){
                                bool found = false;
                                int firstNum;
                                for(int j = 0; j < tableList.size(); ++j){
                                    if(whereClause[i][1] == tableList[j]){
                                        found = true;
                                        firstNum = j;
                                        break;
                                    }
                                }
                                if(!found){
                                    std::cout << "Error : Table not found." << std::endl;
                                    return;
                                }
                                if(firstNum > u) continue;
                                if(whereClause[i][0] == "1"){
                                    if(firstNum != u) continue;
                                    int col = -1;
                                    dbm->getTableColumns(tableList[firstNum], table_cols);
                                    for(int j = 0; j < table_cols.size(); ++j){
                                        if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                            col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            break;
                                        }
                                    }
                                    if(col == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    else
                                        condition.push_back(search_condition(WHERE_NULL * MAX_COLUMN_NUM + col, ""));
                                }
                                else if(whereClause[i][0] == "2"){
                                    if(firstNum != u) continue;
                                    int col = -1;
                                    dbm->getTableColumns(tableList[firstNum], table_cols);
                                    for(int j = 0; j < table_cols.size(); ++j){
                                        if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                            col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                            break;
                                        }
                                    }
                                    if(col == -1){
                                        std::cout << "Error : Column not found" << std::endl;
                                        return;
                                    }
                                    else
                                        condition.push_back(search_condition(WHERE_NOT_NULL * MAX_COLUMN_NUM + col, ""));
                                }
                                else{
                                    if(whereClause[i][4] == "1"){
                                        if(firstNum != u) continue;
                                        dbm->getTableColumns(tableList[firstNum], table_cols);
                                        int col = -1, colr;
                                        for(int j = 0; j < table_cols.size(); ++j){
                                            if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                                col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                                colr = j;
                                                break;
                                            }
                                        }
                                        if(col == -1){
                                            std::cout << "Error : Column not found" << std::endl;
                                            return;
                                        }
                                        if(whereClause[i][3] == "<"
                                        || whereClause[i][3] == ">"
                                        || whereClause[i][3] == "<="
                                        || whereClause[i][3] == ">=")
                                            if(table_cols[colr][N_COLUMN_TYPE][0] != 'i' || whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'){
                                                std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                                return;
                                            }
                                        if((table_cols[colr][N_COLUMN_TYPE][0] == 'i' && (whereClause[i][5][0] < '0' || whereClause[i][5][0] > '9'))
                                        || ((table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') &&  whereClause[i][5][0] != '\'')
                                        || whereClause[i][5] == "null"){
                                            std::cout << "Error : Unmatched compare objects." << std::endl;
                                            return;
                                        }
                                        std::string target;
                                        if(table_cols[colr][N_COLUMN_TYPE][0] == 'c' || table_cols[colr][N_COLUMN_TYPE][0] == 'v') target = whereClause[i][5].substr(1,whereClause[i][5].size()-2);
                                        else target = whereClause[i][5];
                                        int op = -1;
                                        if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                        else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                        else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                        else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                        else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                        else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                        else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                        condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col, target));
                                    }
                                    else{
                                        bool secFound =false;
                                        int secondNum;
                                        for(int j = 0; j < tableList.size(); ++j){
                                            if(tableList[j] == whereClause[i][5]){
                                                secFound = true;
                                                secondNum = j;
                                                break;
                                            }
                                        }
                                        if(!secFound){
                                            std::cout << "Error : Table not found." << std::endl;
                                            return;
                                        }
                                        if(firstNum != u && secondNum != u) continue;
                                        if(firstNum > u || secondNum > u) continue;
                                        dbm->getTableColumns(tableList[firstNum], table_cols);
                                        string type1;
                                        int col = -1, colr;
                                        for(int j = 0; j < table_cols.size(); ++j){
                                            if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][2], table_cols[j][N_COLUMN_NAME].size())){
                                                col = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                                colr = j;
                                                type1 = table_cols[j][N_COLUMN_TYPE];
                                                break;
                                            }
                                        }
                                        if(col == -1){
                                            std::cout << "Error : Column not found" << std::endl;
                                            return;
                                        }
                                        dbm->getTableColumns(tableList[secondNum], table_cols);
                                        int col2 = -1;
                                        string type2;
                                        for(int j = 0; j < table_cols.size(); ++j){
                                            if(table_cols[j][N_COLUMN_NAME] == Data::fillStr(whereClause[i][6], table_cols[j][N_COLUMN_NAME].size())){
                                                col2 = Data::intUnzip(&(table_cols[j][N_COLUMN_RANK][0]), MAX_COLUMN_RANK);
                                                type2 = table_cols[j][N_COLUMN_TYPE];
                                                break;
                                            }
                                        }
                                        if(col2 == -1){
                                            std::cout << "Error : Column not found" << std::endl;
                                            return;
                                        }
                                        if(whereClause[i][3] == "<"
                                        || whereClause[i][3] == ">"
                                        || whereClause[i][3] == "<="
                                        || whereClause[i][3] == ">=")
                                            if(type1[0] != 'i'){
                                                std::cout << "Error : Operator " << whereClause[i][3] << " can only be used between integer." << std::endl;
                                                return;
                                            }
                                        if(type1 != type2){
                                            std::cout << "Error : Unmatched compare objects." << std::endl;
                                            return;
                                        }
                                        int op = -1;
                                        if(whereClause[i][3] == "=") op = WHERE_OP_EQUAL;
                                        else if(whereClause[i][3] == "<>") op = WHERE_OP_NOT_EQUAL;
                                        else if(whereClause[i][3] == "<") op = WHERE_OP_LESS;
                                        else if(whereClause[i][3] == ">") op = WHERE_OP_MORE;
                                        else if(whereClause[i][3] == "<=") op = WHERE_OP_LTE;
                                        else if(whereClause[i][3] == ">=") op = WHERE_OP_GTE;
                                        else if(whereClause[i][3] == "like") op = WHERE_OP_LIKE;
                                        if(firstNum == secondNum){
                                            std::string target;
                                    		std::stringstream ss;
                                    		ss << col2;
                                    		ss >> target;
                                            condition.push_back(search_condition((op * WHERE_TYPE_NUM + WHERE_OP_COL) * MAX_COLUMN_NUM + col, target));
                                        }
                                        else{
                                            bool found = false;
                                            position newp = position(col * tableList.size() + firstNum, col2 * tableList.size() + secondNum);
                                            for(int k = 0; k < replace.size(); ++k){
                                                if(replace[k].first == newp.first && replace[k].second == newp.second){
                                                    found = true;
                                                    break;
                                                }
                                            }
                                            if(!found){
                                                replace.push_back(newp);
                                                replace_op.push_back(op);
                                            }
                                        }
                                    }
                                }
                            }
                            conditions.push_back(condition);
                        }
                        search_result final_res;
                        std::vector<int> complete_table;
                        complete_table.clear();
                        int min_num = -1;
                        for(int i = 0; i < tableList.size(); ++i){
                            search_result res;
                            dbm->getDataManager()->searchData(conditions[i], tableList[i], res);
                            if(min_num == -1 || res.size() < final_res.size()){
                                final_res = res;
                                min_num = i;
                            }
                        }
                        std::vector<int> table_col_num;
                        std::vector<std::string> tList = tableList;
                        for(int i = 0 ; i < tableList.size(); ++i){
                            std::vector<std::vector<std::string> > tbcols;
                            dbm->getTableColumns(tableList[i], tbcols);
                            table_col_num.push_back(tbcols.size() + 1);
                        }
                        complete_table.push_back(min_num);
                        tableList[min_num] = "";
                        while(complete_table.size() < tableList.size()){
                            search_result min_res;
                            min_res.clear();
                            min_num = -1;
                            for(int i = 0; i < tableList.size(); ++i){
                                if(tableList[i] == "") continue;
                                search_result res;
                                res.clear();
                                std::vector<std::pair<int,int> > singleRep;
                                for(int j = 0; j < replace.size(); ++j){
                                    if((replace[j].first%tableList.size()) == i){
                                        int col = replace[j].first/tableList.size();
                                        int rt = replace[j].second%tableList.size();
                                        int rc = replace[j].second/tableList.size();
                                        bool found = false;
                                        int targetCol = 0;
                                        for(int k = 0; k < complete_table.size(); ++k){
                                            if(rt == complete_table[k]){
                                                found = true;
                                                targetCol += rc;
                                                break;
                                            }
                                            targetCol += table_col_num[complete_table[k]];
                                        }
                                        if(!found) continue;
                                        singleRep.push_back(std::pair<int,int>((replace_op[j] * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col,targetCol));
                                    }
                                    else if((replace[j].second%tableList.size()) == i){
                                        int col = replace[j].second/tableList.size();
                                        int rt = replace[j].first%tableList.size();
                                        int rc = replace[j].first/tableList.size();
                                        bool found = false;
                                        int targetCol = 0;
                                        for(int k = 0; k < complete_table.size(); ++k){
                                            if(rt == complete_table[k]){
                                                found = true;
                                                targetCol += rc;
                                                break;
                                            }
                                            targetCol += table_col_num[complete_table[k]];
                                        }
                                        if(!found) continue;
                                        int op = replace_op[j];
                                        if(op == WHERE_OP_LTE) op = WHERE_OP_GTE;
                                        else if(op == WHERE_OP_GTE) op = WHERE_OP_LTE;
                                        else if(op == WHERE_OP_LESS) op = WHERE_OP_MORE;
                                        else if(op == WHERE_OP_MORE) op = WHERE_OP_LESS;
                                        singleRep.push_back(std::pair<int,int>((op * WHERE_TYPE_NUM + WHERE_OP_VAL) * MAX_COLUMN_NUM + col,targetCol));
                                    }
                                }
                                for(int j = 0; j < final_res.size(); ++j){
                                    std::vector<search_condition> tempCon = conditions[i];
                                    search_result tempRes;
                                    tempRes.clear();
                                    for(int k = 0; k < singleRep.size(); ++k)
                                        tempCon.push_back(search_condition(singleRep[k].first, final_res[j][singleRep[k].second]));
                                    dbm->getDataManager()->searchData(tempCon, tableList[i], tempRes);
                                    for(int k = 0; k < tempRes.size(); ++k){
                                        std::vector<std::string> singleRes = final_res[j];
                                        for(int t = 0; t < tempRes[k].size(); ++t) singleRes.push_back(tempRes[k][t]);
                                        res.push_back(singleRes);
                                    }
                                }
                                if(res.size() < min_res.size() || min_num == -1){
                                    min_num = i;
                                    min_res = res;
                                }
                            }
                            tableList[min_num] = "";
                            complete_table.push_back(min_num);
                            final_res = min_res;
                        }
                        for(int i = 0; i < tList.size(); ++i){
                            std::vector<std::vector<std::string> > table_cols;
                            dbm->getTableColumns(tList[i], table_cols);
                            for(int j = 0; j < select_cols[i].size(); ++j){
                                for(int k = 0; k < table_cols.size(); ++k){
                                    if(Data::intUnzip(&(table_cols[k][N_COLUMN_RANK][0]), MAX_COLUMN_RANK) == select_cols[i][j]){
                                        std::cout << tList[i] << "." << table_cols[k][N_COLUMN_NAME].c_str() << " | ";
                                    }
                                }
                            }
                        }
                        std::cout << std::endl;
                        for(int u = 0; u < final_res.size(); ++u){
                            for(int i = 0; i < tList.size(); ++i){
                                int tcol = 0;
                                for(int k = 0; k < complete_table.size(); ++k){
                                    if(i == complete_table[k])
                                        break;
                                    tcol += table_col_num[complete_table[k]];
                                }
                                for(int j = 0; j < select_cols[i].size(); ++j){
                                    std::cout << final_res[u][tcol + select_cols[i][j]].c_str() << " | ";
                                }
                            }
                            std::cout << std::endl;
                        }
                        std::cout << std::endl;
                        std::cout << "Time cost : " << clock() - t1 << " ms" << std::endl;
                    }
                }
            }
            else
                syntaxError();
        }
    }
    bool getTableList(std::vector<std::string>& tableList){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        tableList.clear();
        std::string table;
        while(true){
            if(tableList.size() == 0){
                if(!getIdentifier(table)) return false;
                tableList.push_back(table);
            }
            else{
                if(loc < words.size() && words[loc] == ","){
                    if(!MatchToken(",")) return false;
                    if(!getIdentifier(table)) return false;
                    tableList.push_back(table);
                }
                else break;
            }
        }
        return true;
    }
    bool getSelector(std::vector<std::string>& selector){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        selector.clear();
        if(words[loc] == "*"){
            selector.push_back(words[loc]);
            MatchToken("*");
            return true;
        }
        else{
            std::vector<std::string> col;
            while(true){
                if(selector.size() == 0){
                    if(!getCol(col)) return false;
                    for(int i = 0; i < col.size(); ++i)
                        selector.push_back(col[i]);
                }
                else{
                    if(loc < words.size() && words[loc] == ","){
                        if(!MatchToken(",")) return false;
                        if(!getCol(col)) return false;
                        for(int i = 0; i < col.size(); ++i)
                            selector.push_back(col[i]);
                    }
                    else break;
                }
            }
        }
        return true;
    }
    bool getSetClause(std::vector<std::vector<std::string> >& setClause){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        setClause.clear();
        std::vector<std::string> singleSet;
        while(true){
            if(setClause.size() == 0){
                if(!getSingleSet(singleSet)) return false;
                setClause.push_back(singleSet);
            }
            else{
                if(loc < words.size() && lowercase(words[loc]) == ","){
                    if(!MatchToken(",")) return false;
                    if(!getSingleSet(singleSet)) return false;
                    setClause.push_back(singleSet);
                }
                else break;
            }
        }
        return true;
    }
    bool getWhereClause(std::vector<std::vector<std::string> >& whereClause){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        whereClause.clear();
        std::vector<std::string> singleWhere;
        while(true){
            if(whereClause.size() == 0){
                if(!getSingleWhere(singleWhere)) return false;
                whereClause.push_back(singleWhere);
            }
            else{
                if(loc < words.size() && lowercase(words[loc]) == "and"){
                    if(!MatchToken("and")) return false;
                    if(!getSingleWhere(singleWhere)) return false;
                    whereClause.push_back(singleWhere);
                }
                else break;
            }
        }
        return true;
    }
    bool getSingleSet(std::vector<std::string>& singleSet){
        if(loc + 2 >= words.size()){
            syntaxError();
            return false;
        }
        singleSet.clear();
        std::string colName;
        if(!getIdentifier(colName)) return false;
        if(!MatchToken("=")) return false;
        std::string value;
        if(!getValue(value)) return false;
        singleSet.push_back(colName);
        singleSet.push_back(value);
        return true;
    }
    bool getSingleWhere(std::vector<std::string>& singleWhere){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        singleWhere.clear();
        std::vector<std::string> col;
        if(!getCol(col)) return false;
        if(loc + 1 < words.size() && lowercase(words[loc]) == "is" && lowercase(words[loc+1]) == "null"){
            loc += 2;
            singleWhere.push_back("1");
            for(int i = 0; i < col.size(); ++i)
                singleWhere.push_back(col[i]);
            return true;
        }
        else if(loc + 2 < words.size() && lowercase(words[loc]) == "is" && lowercase(words[loc+1]) == "not" && lowercase(words[loc+2]) == "null"){
            loc += 3;
            singleWhere.push_back("2");
            for(int i = 0; i < col.size(); ++i)
                singleWhere.push_back(col[i]);
            return true;
        }
        else{
            singleWhere.push_back("3");
            for(int i = 0; i < col.size(); ++i)
                singleWhere.push_back(col[i]);
            std::string op;
            if(!getOp(op)) return false;
            singleWhere.push_back(op);
            std::vector<std::string> expr;
            if(!getExpr(expr)) return false;
            for(int i = 0; i < expr.size(); ++i)
                singleWhere.push_back(expr[i]);
            return true;
        }
    }
    bool getExpr(std::vector<std::string> &expr){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        expr.clear();
        if((words[loc][0] >= '0' && words[loc][0] <= '9')
        || words[loc][0] == '\'' || lowercase(words[loc]) == "null"){
            std::string value;
            if(!getValue(value)) return false;
            expr.push_back("1");
            expr.push_back(value);
            return true;
        }
        else{
            if(!getCol(expr)) return false;
            expr.insert(expr.begin(), "2");
            return true;
        }
    }
    bool getOp(std::string &op){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        if(lowercase(words[loc]) == "like" || words[loc] == "=" || words[loc] == "<>" || words[loc] == "<=" || words[loc] == ">=" || words[loc] == "<" || words[loc] == ">"){
            op = lowercase(words[loc]);
            ++ loc;
            return true;
        }
        else{
            syntaxError();
            return false;
        }
    }
    bool getCol(std::vector<std::string>& col){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        col.clear();
        if(loc + 2 >= words.size()){
            std::string colName;
            if(!getIdentifier(colName)) return false;
            col.push_back("");
            col.push_back(colName);
            return true;
        }
        else if(words[loc+1] == "."){
            std::string tbName, colName;
            if(!getIdentifier(tbName)) return false;
            if(!MatchToken(".")) return false;
            if(!getIdentifier(colName)) return false;
            col.push_back(tbName);
            col.push_back(colName);
            return true;
        }
        else{
            std::string colName;
            if(!getIdentifier(colName)) return false;
            col.push_back("");
            col.push_back(colName);
            return true;
        }
    }
    bool getValueLists(std::vector<std::vector<std::string> >& vList){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        vList.clear();
        std::vector<std::string> value;
        while(true){
            if(vList.size() == 0){
                if(!MatchToken("(")) return false;
                if(!getValueList(value)) return false;
                vList.push_back(value);
                if(!MatchToken(")")) return false;
            }
            else{
                if(loc < words.size() && words[loc] == ","){
                    MatchToken(",");
                    if(!MatchToken("(")) return false;
                    if(!getValueList(value)) return false;
                    vList.push_back(value);
                    if(!MatchToken(")")) return false;
                }
                else break;
            }
        }
        return true;
    }
    bool getValueList(std::vector<std::string>& vList){
        vList.clear();
        std::string value;
        while(true){
            if(vList.size() == 0){
                if(!getValue(value)) return false;
                vList.push_back(value);
            }
            else{
                if(loc < words.size() && words[loc] == ","){
                    MatchToken(",");
                    if(!getValue(value)) return false;
                    vList.push_back(value);
                }
                else break;
            }
        }
        return true;
    }
    bool getValue(std::string& value){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        if(words[loc][0] == '\'' && words[loc][words[loc].length()-1] == '\''){
            value = words[loc];
            ++loc;
            return true;
        }
        else if(lowercase(words[loc]) == "null"){
            value = lowercase(words[loc]);
            ++loc;
            return true;
        }
        else if(isNum(words[loc])){
            value = words[loc];
            ++loc;
            return true;
        }
        else{
            syntaxError();
            return false;
        }
    }
    bool getFieldList(std::vector<std::vector<std::string> >& flist){
        flist.clear();
        std::vector<std::string> field;
        while(true){
            if(flist.size() == 0){
                if(!getField(field)) return false;
                flist.push_back(field);
            }
            else{
                if(loc < words.size() && words[loc] == ","){
                    MatchToken(",");
                    if(!getField(field)) return false;
                    flist.push_back(field);
                }
                else break;
            }
        }
        return true;
    }
    bool getField(std::vector<std::string>& field){
        field.clear();
        if(loc + 1 >= words.size()){
            syntaxError();
            return false;
        }
        else if(lowercase(words[loc]) == "check"){
            field.push_back("4");
            loc += 1;
            if(!MatchToken("(")) return false;
            std::string colName;
            if(!getIdentifier(colName)) return false;
            field.push_back(colName);
            if(!MatchToken("in")) return false;
            if(!MatchToken("(")) return false;
            std::vector<std::string> valList;
            if(!getValueList(valList)) return false;
            for(int i = 0; i < valList.size(); ++i)
                field.push_back(valList[i]);
            if(!MatchToken(")")) return false;
            if(!MatchToken(")")) return false;
            return true;
        }
        else if(lowercase(words[loc]) == "primary" && lowercase(words[loc+1]) == "key"){
            field.push_back("3");
            loc += 2;
            if(!MatchToken("(")) return false;
            std::string colName;
            if(!getIdentifier(colName)) return false;
            field.push_back(colName);
            if(!MatchToken(")")) return false;
            return true;
        }
        else{
            std::string type, len, colName;
            field.push_back("1");
            if(!getIdentifier(colName)) return false;
            field.push_back(colName);
            if(!getType(type, len)) return false;
            field.push_back(type);
            field.push_back(len);
            if(loc+1>= words.size()) {}
            else if(lowercase(words[loc]) == "not" && lowercase(words[loc+1]) == "null") field[0] = "2";
            else {}
            if(field[0] == "2") loc += 2;
            return true;
        }
    }
    bool getType(std::string &type, std::string &len){
        if(loc + 3 >= words.size()){
            syntaxError();
            return false;
        }
        type = words[loc];
        ++loc;
        if(!MatchToken("(")) return false;
        len = words[loc];
        ++loc;
        if(!MatchToken(")")) return false;
        return true;
    }
    bool getIdentifier(std::string &str){
        if(loc >= words.size()){
            syntaxError();
            return false;
        }
        str = words[loc];
        bool legal = true;
        if(str.size() == 0) legal = false;
        else if(!((str[0] >= 'a' && str[0] <= 'z') || (str[0] >= 'A' && str[0] <= 'Z'))) legal = false;
        else{
            for(int i = 1; i < str.size(); ++i){
                if(!((str[0] >= 'a' && str[0] <= 'z') || (str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= '0' && str[0] <= '9') || str[0] == '_')){
                    legal = false;
                    break;
                }
            }
        }
        if(!legal){
            std::cout << "Error : Unexpected identifier" << std::endl;
            return false;
        }
        ++loc;
        return true;
    }
    void splitWords(std::string &command){
        words.clear();
        bool strStart = false;
        int cmdLen = command.size();
        command += "$$$$$$";
        std::string word = "";
        for(int i = 0; i < cmdLen; ++i){
            if(strStart && command[i] != '\'' && command[i] != '\\') word += command[i];
            else{
                if(command[i] == ' '){
                    if(word != ""){
                        words.push_back(word);
                        word = "";
                    }
                }
                else if(command[i] == '.' || command[i] == '(' || command[i] == ')' || command[i] == ',' || command[i] == '=' || command[i] == '*'){
                    if(word != ""){
                        words.push_back(word);
                        word = "";
                    }
                    words.push_back(word+command[i]);
                }
                else if(command[i] == '\''){
                    if(strStart){
                        word += command[i];
                        words.push_back(word);
                        word = "";
                    }
                    else{
                         if(word != ""){
                            words.push_back(word);
                            word = "";
                        }
                        word += command[i];
                    }
                    strStart = !strStart;
                }
                else if((command[i] == '<' && command[i+1] == '>')
                    ||  (command[i] == '<' && command[i+1] == '=')
                    ||  (command[i] == '>' && command[i+1] == '=')){
                    if(word != ""){
                        words.push_back(word);
                        word = "";
                    }
                    words.push_back(command.substr(i,2));
                    ++i;
                }
                else if((command[i] == '\\' && command[i+1] == '\'')
                    ||  (command[i] == '\\' && command[i+1] == '\"')){
                    word += command[i+1];
                    ++i;
                }
                else if(command[i] == '<' || command[i] == '>'){
                    if(word != ""){
                        words.push_back(word);
                        word = "";
                    }
                    words.push_back(word+command[i]);
                }
                else
                    word += command[i];
            }
        }
        if(word != "") words.push_back(word);
    }
};

#endif // COMMAND_ANALYSER_H
